package api

import (
	"context"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/signal"
	"path/filepath"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"go-papers/cache"
	"go-papers/pkg/aliyun"

	"go-papers/database"
	"go-papers/models/mysql"
	"go-papers/pkg/lognew"
	"go-papers/pkg/redis"
	"go-papers/pkg/sql"
	"go-papers/pkg/wechat"
	"go-papers/router"
	"go-papers/tools"
	config2 "go-papers/tools/config"
)

var (
	config   string
	port     string
	mode     string
	StartCmd = &cobra.Command{
		Use:     "server",
		Short:   "Start API server",
		Example: "go-papers server config/settings.yml",
		PreRun: func(cmd *cobra.Command, args []string) {
			usage()
			setup()
		},
		RunE: func(cmd *cobra.Command, args []string) error {
			return run()
		},
	}
)

func init() {
	StartCmd.PersistentFlags().StringVarP(&config, "config", "c", "config/", "Start server with provided configuration file")
	StartCmd.PersistentFlags().StringVarP(&port, "port", "p", "8000", "Tcp port server listening on")
	StartCmd.PersistentFlags().StringVarP(&mode, "mode", "m", "local", "server mode ; eg:dev,test,prod")
}

func usage() {
	// usageStr := `starting api server`
	// fmt.Printf("%s\n", usageStr)
}

func setup() {

	// 如果config使用的是绝对路径，则config为路径，mode为文件名
	if filepath.IsAbs(config) {
		config, mode = filepath.Split(config)
		log.Println("config:", config, "  mode:", mode)
	} else {
		if mode == "prod" {
			config = "config/"
		}
		log.Println("Default LIST config:", config, "  mode:", mode)
	}

	// 1. 读取配置 初始化公共配置
	config2.InitGconfig(mode, config)

	// 2. 设置日志
	tools.InitLogger()
	lognew.Init()
	// 初始化公共组件
	// 初始化 redis 组件
	redis.Init()
	// 初始化 httpclient 组件
	// httpclient.Init()
	// 初始化 nsq 组件
	// nsq.Init()
	// 初始化 mysql 组件
	sql.Init()

	// 3. 初始化数据库链接
	cache.Init()

	wechat.Init()
	aliyun.Init()

	// 初始化 oss 组件
	// oss.Init()

	mysql.Init()
	database.Setup()

	//4. 设置gin mode
	if viper.GetString("settings.application.mode") == string(tools.ModeProd) {
		gin.SetMode(gin.ReleaseMode)
	} else {
		gin.SetMode(gin.TestMode)
	}
}

func run() error {

	r := router.InitRouter()

	defer database.Eloquent.Close()

	cfg := config2.GConfig.Transport.HTTP
	srv := &http.Server{
		Addr: cfg.Addr,
		//Handler:           enghttp.NewHTTPHandler(),
		Handler:           r,
		ReadTimeout:       time.Duration(cfg.ReadTimeout*1000) * time.Millisecond,
		ReadHeaderTimeout: time.Duration(cfg.ReadHeaderTimeout*1000) * time.Millisecond,
		WriteTimeout:      time.Duration(cfg.WriteTimeout*1000) * time.Millisecond,
		IdleTimeout:       time.Duration(cfg.IdleTimeout*1000) * time.Millisecond,
		MaxHeaderBytes:    4 << 20,
	}

	go func() {
		// 服务连接
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("listen: %s\n", err)
		}
	}()

	content, _ := ioutil.ReadFile("./static/go-admin.txt")
	log.Println(string(content))
	log.Println("Server Run http://127.0.0.1" + cfg.Addr + "/")
	//log.Println("Swagger URL http://127.0.0.1" + cfg.Addr + "/swagger/index.html")

	log.Println("Enter Control + C Shutdown Server")

	// 等待中断信号以优雅地关闭服务器（设置 5 秒的超时时间）
	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt)
	<-quit
	log.Println("Shutdown Server ...")

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := srv.Shutdown(ctx); err != nil {
		log.Fatal("Server Shutdown:", err)
	}
	log.Println("Server exiting")
	return nil
}
